package com.mrx.xcitools.service;

import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.PreDestroy;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import static com.mrx.xcitools.constant.FileConstant.*;

/**
 * @author Mr.X
 * @since 2024-03-11 15:22
 **/
@Service
public class ProcessManageService {

    private static final Map<String, Process> processMap = new ConcurrentHashMap<>();

    private static final Logger logger = LoggerFactory.getLogger(ProcessManageService.class);

    @SneakyThrows
    public long runProcess(File jarFile, String... command) {
        String jarPath = jarFile.getAbsolutePath();
        if (command == null) {
            command = new String[0];
        }
        List<String> commands = new ArrayList<>(command.length + 3);
        commands.addAll(List.of("java", "-jar", "-Xms128m", "-Xmx256m", jarPath));
        commands.addAll(List.of(command));
        File workDir = getWorkDir(jarFile.getName());
        if (!workDir.exists()) {
            if (workDir.mkdirs()) {
                logger.info("创建 {} 的数据目录", jarPath);
            }
        }
        logger.info("启动 {}, 命令 {}", jarPath, commands);
        ProcessBuilder builder = new ProcessBuilder().directory(workDir).command(commands);
        builder.redirectOutput(getLogFile(workDir, OUT_PUT_LOG));
        builder.redirectError(getLogFile(workDir, ERROR_LOG));
        Process process = builder.start();
        process.onExit().thenAccept(this::onExit);
        processMap.put(jarFile.getName(), process);
        return process.pid();
    }

    public boolean stopProcess(String jarName) {
        logger.info("结束进程: {}", jarName);
        Process process = processMap.get(jarName);
        if (process != null) {
            process.destroy();
            return true;
        }
        return false;
    }

    public Long getProcessId(String jarName) {
        return Optional.ofNullable(processMap.get(jarName)).map(Process::pid).orElse(null);
    }

    @SneakyThrows
    public String getLog(String jarName, String logFile, Integer line) {
        Process process = processMap.get(jarName);
        Assert.notNull(process, "进程不存在");
        File workDir = getWorkDir(jarName);
        List<String> lines = Files.readAllLines(getLogFile(workDir, logFile).toPath());
        int from = Math.max(lines.size() - line, 0);
        return String.join("\n", lines.subList(from, lines.size()));
    }

    @PreDestroy
    public void onDestroy() {
        if (processMap.isEmpty()) {
            return;
        }
        logger.info("关闭所有启动的服务: {}", processMap.keySet());
        processMap.values().forEach(Process::destroy);
    }

    private File getLogFile(File workDir, String fileName) {
        return new File(workDir, fileName);
    }

    private File getWorkDir(String jarName) {
        return new File(JAR_DATA_DIR, jarName);
    }

    private void onExit(Process process) {
        List<String> exitedProcess = processMap.entrySet().stream()
                .filter(it -> it.getValue().pid() == process.pid()).map(Map.Entry::getKey)
                .toList();
        logger.info("进程结束: {}", exitedProcess);
        exitedProcess.forEach(processMap::remove);
    }

}
